package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderDerateService;
import com.atguigu.tingshu.order.service.OrderDetailService;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.account.AccountDeductVo;
import com.atguigu.tingshu.vo.order.*;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderDerateService orderDerateService;

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;
    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;
    @Autowired
    private UserAccountFeignClient userAccountFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RabbitService rabbitService;

    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        //初始化订单信息
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //订单原始金额
        BigDecimal originalAmount = new BigDecimal("0.00");
        //减免总金额
        BigDecimal derateAmount = new BigDecimal("0.00");
        //订单总金额
        BigDecimal orderAmount = new BigDecimal("0.00");
        //订单明细列表
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        //订单减免明细列表
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
        //订单明细对象
        OrderDetailVo orderDetailVo = new OrderDetailVo();
        //订单减免明细对象
        OrderDerateVo orderDerateVo = new OrderDerateVo();
        String tradeNo = UUID.randomUUID().toString().replaceAll("-", "");
        String tradeNoKey = userId + ":" + tradeNo;
        this.redisTemplate.opsForValue().setIfAbsent(tradeNoKey, tradeNo, 10, TimeUnit.MINUTES);
        orderInfoVo.setTradeNo(tradeNo);
        orderInfoVo.setPayWay("");
        String itemType = tradeVo.getItemType();
        orderInfoVo.setItemType(itemType);
        switch (itemType) {
            case SystemConstant.ORDER_ITEM_TYPE_ALBUM:
                //专辑
                Result<Boolean> result = userInfoFeignClient.isPaidAlbum(tradeVo.getItemId());
                Assert.notNull(result, "用户远程调用失败");
                Boolean resultData = result.getData();
                if (resultData) {
                    //已购买，直接返回数据
                    throw new GuiguException(ResultCodeEnum.REPEAT_BUY_ERROR);
                }
                Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(tradeVo.getItemId());
                Assert.notNull(albumInfoResult, "专辑远程调用失败");
                AlbumInfo albumInfo = albumInfoResult.getData();
                Assert.notNull(albumInfo, "专辑为空");
                originalAmount = albumInfo.getPrice();
                if (albumInfo.getDiscount().compareTo(new BigDecimal("-1")) > 0) {
                    //有折扣
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getDiscount()))
                            .divide(new BigDecimal("10"), 2, BigDecimal.ROUND_UP);
                }
                if (albumInfo.getVipDiscount().compareTo(new BigDecimal("-1")) > 0) {
                    //有vip折扣
                    Result<UserInfo> userInfoResult = userInfoFeignClient.getUserInfo(userId);
                    Assert.notNull(userInfoResult, "用户远程调用失败");
                    UserInfo userInfo = userInfoResult.getData();
                    Assert.notNull(userInfo, "用户为空");
                    if (userInfo.getIsVip() == 1 && userInfo.getVipExpireTime().after(new Date())) {
                        //用户vip未过期
                        derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getVipDiscount()))
                                .divide(new BigDecimal("10"), 2, BigDecimal.ROUND_UP);
                    }
                }
                orderAmount = originalAmount.subtract(derateAmount);
                //添加订单明细
                orderDetailVo.setItemId(tradeVo.getItemId());
                orderDetailVo.setItemName(albumInfo.getAlbumTitle());
                orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
                orderDetailVo.setItemPrice(orderAmount);
                orderDetailVoList.add(orderDetailVo);
                //添加订单减免明细列表
                if (derateAmount.compareTo(new BigDecimal("0.00")) > 0) {
                    orderDerateVo.setDerateAmount(derateAmount);
                    orderDerateVo.setDerateType("1405");
                    orderDerateVo.setRemarks("专辑折扣");
                    orderDerateVoList.add(orderDerateVo);
                }
                break;
            case SystemConstant.ORDER_ITEM_TYPE_TRACK:
                //声音  itemId:声音id
                //远程调用获取声音信息
                Result<List<TrackInfo>> trackInfoResult = trackInfoFeignClient.getTrackListById(tradeVo.getItemId(), tradeVo.getTrackCount());
                Assert.notNull(trackInfoResult, "声音远程调用失败");
                List<TrackInfo> trackInfoList = trackInfoResult.getData();
                Assert.notNull(trackInfoList, "声音为空");
                //获取专辑id
                Long albumId = trackInfoList.get(0).getAlbumId();
                Result<AlbumInfo> albumInfoResult1 = albumInfoFeignClient.getAlbumInfo(albumId);
                Assert.notNull(albumInfoResult1, "专辑远程调用失败");
                AlbumInfo albumInfo1 = albumInfoResult1.getData();
                Assert.notNull(albumInfo1, "专辑为空");
                originalAmount = tradeVo.getTrackCount() == 0 ? albumInfo1.getPrice() : albumInfo1.getPrice().multiply(new BigDecimal(tradeVo.getTrackCount()));
                orderAmount = originalAmount;
                //封装订单明细列表
                for (TrackInfo trackInfo : trackInfoList) {
                    orderDetailVo = new OrderDetailVo();
                    orderDetailVo.setItemId(trackInfo.getId());
                    orderDetailVo.setItemName(trackInfo.getTrackTitle());
                    orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                    orderDetailVo.setItemPrice(albumInfo1.getPrice());
                    orderDetailVoList.add(orderDetailVo);
                }
                break;
            case SystemConstant.ORDER_ITEM_TYPE_VIP:
                //vip
                //获取vip服务配置
                Result<VipServiceConfig> vipServiceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(tradeVo.getItemId());
                Assert.notNull(vipServiceConfigResult, "vip远程调用失败");
                VipServiceConfig vipServiceConfig = vipServiceConfigResult.getData();
                Assert.notNull(vipServiceConfig, "vip服务为空");
                originalAmount = vipServiceConfig.getPrice();
                orderAmount = vipServiceConfig.getDiscountPrice();
                derateAmount = originalAmount.subtract(orderAmount);
                //添加订单明细
                orderDetailVo.setItemId(tradeVo.getItemId());
                orderDetailVo.setItemName(vipServiceConfig.getName());
                orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
                orderDetailVo.setItemPrice(orderAmount);
                orderDetailVoList.add(orderDetailVo);
                //添加订单减免明细列表
                if (derateAmount.compareTo(new BigDecimal("0.00")) > 0) {
                    orderDerateVo.setDerateAmount(derateAmount);
                    orderDerateVo.setDerateType("1406");
                    orderDerateVo.setRemarks("VIP服务折扣");
                    orderDerateVoList.add(orderDerateVo);
                }
                break;
        }
        //设置订单原始金额
        orderInfoVo.setOriginalAmount(originalAmount);
        //设置减免金额
        orderInfoVo.setDerateAmount(derateAmount);
        //设置订单总金额
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        orderInfoVo.setTimestamp(SignHelper.getTimestamp());
        orderInfoVo.setSign(SignHelper.getSign(JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class)));
        return orderInfoVo;
    }

    @Override
    @GlobalTransactional
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //检验流水号     检验签名    判断支付类型
        String tradeNo = orderInfoVo.getTradeNo();
        // 获取分布式锁
        String lockKey = userId + ":" + tradeNo + ":lock";
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        // 判断redis中是否有该订单
        try {
            String tradeNoKey = userId + ":" + tradeNo;
            String redisTradeNo = (String) redisTemplate.opsForValue().get(tradeNoKey);
            if (StringUtils.isEmpty(redisTradeNo)){
                //订单重复提交
                throw new GuiguException(ResultCodeEnum.ORDER_SUBMIT_REPEAT);
            }else {
                // 删除redis中的订单号
                redisTemplate.delete(tradeNoKey);
            }
        } finally {
            lock.unlock();
        }
        // 校验签名
        Map map = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        map.put("payWay","");
        SignHelper.checkSign(map);
        // 生成订单号
        String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
        // 判断支付类型
        if (SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(orderInfoVo.getPayWay())){
            //微信支付
            saveOrder(orderInfoVo,orderNo,userId);
            // 发送延迟消息，到时间删除订单
            rabbitService.sendDealyMessage(MqConst.EXCHANGE_CANCEL_ORDER,MqConst.ROUTING_CANCEL_ORDER,orderNo,MqConst.CANCEL_ORDER_DELAY_TIME);
            //todo: 微信支付
        }else if (SystemConstant.ORDER_PAY_WAY_ALIPAY.equals(orderInfoVo.getPayWay())){
            //支付宝支付
        }else if (SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())){
            //账户余额支付

            //保存所有订单信息
            saveOrder(orderInfoVo,orderNo,userId);
            //扣减余额
            AccountDeductVo accountDeductVo = new AccountDeductVo();
            accountDeductVo.setOrderNo(orderNo);
            accountDeductVo.setAmount(orderInfoVo.getOrderAmount());
            accountDeductVo.setUserId(userId);
            accountDeductVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
            Result<Boolean> result = userAccountFeignClient.checkAndDeduct(accountDeductVo);
            if (result.getCode()!=200){
                //余额扣减失败
                throw new GuiguException(result.getCode(),result.getMessage());
            }
            //订单支付成功，修改订单状态
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
            orderInfoMapper.update(orderInfo,new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo,orderNo));
            //记录用户购买记录
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setUserId(userId);
            userPaidRecordVo.setOrderNo(orderNo);
            userPaidRecordVo.setItemType(orderInfoVo.getItemType());
            userPaidRecordVo.setItemIdList(orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList()));
            result = userInfoFeignClient.saveUserPaidRecord(userPaidRecordVo);
            if (result.getCode()!=200){
                //记录用户购买记录失败
                throw new GuiguException(211, "新增购买记录异常");
            }
        }
        return orderNo;
    }

    @Override
    public OrderInfo getOrderInfo(String orderNo) {
        OrderInfo orderInfo = getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        List<OrderDerate> derateList = orderDerateService.list(new LambdaQueryWrapper<OrderDerate>().eq(OrderDerate::getOrderId, orderInfo.getId()));
        orderInfo.setOrderDerateList(derateList);
        List<OrderDetail> detailList = orderDetailService.list(new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, orderInfo.getId()));
        orderInfo.setOrderDetailList(detailList);
        orderInfo.setPayWayName(SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(orderInfo.getPayWay())?"微信支付":
                SystemConstant.ORDER_PAY_WAY_ALIPAY.equals(orderInfo.getPayWay())?"支付宝支付":"账户余额支付");
        return orderInfo;
    }

    @Override
    public void findUserPage(Page<OrderInfo> page, Long userId, String orderStatus) {
        page=orderInfoMapper.findUserPage(page,userId,orderStatus);
    }

    @Override
    public void cancelOrder(String orderNo) {
        // 判断订单状态
        OrderInfo orderInfo = getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        if (!orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_UNPAID)){
            //订单已付款或已取消，无需取消
            return;
        }
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
        updateById(orderInfo);
    }

    /**
     * 保存订单信息
     * @param orderInfoVo
     * @param orderNo
     * @param userId
     */
    @Transactional(rollbackFor = Exception.class)
    private void saveOrder(OrderInfoVo orderInfoVo, String orderNo, Long userId) {
        //添加order_info表单
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVo,orderInfo);
        orderInfo.setUserId(userId);
        orderInfo.setOrderNo(orderNo);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        orderInfoMapper.insert(orderInfo);
        //添加order_detail表单
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        if (!CollectionUtils.isEmpty(orderDetailVoList)){
            List<OrderDetail> detailList = orderDetailVoList.stream().map(orderDetailVo -> {
                OrderDetail orderDetail = new OrderDetail();
                BeanUtils.copyProperties(orderDetailVo, orderDetail);
                orderDetail.setOrderId(orderInfo.getId());
                return orderDetail;
            }).collect(Collectors.toList());
            orderDetailService.saveBatch(detailList);
        }
        //添加order_derate表单
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if (!CollectionUtils.isEmpty(orderDerateVoList)){
            List<OrderDerate> derateList = orderDerateVoList.stream().map(orderDerateVo -> {
                OrderDerate orderDerate = new OrderDerate();
                BeanUtils.copyProperties(orderDerateVo, orderDerate);
                orderDerate.setOrderId(orderInfo.getId());
                return orderDerate;
            }).collect(Collectors.toList());
            orderDerateService.saveBatch(derateList);
        }
    }
}
